home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / gnu / amiga / bmake15.lzh / expand.c < prev    next >
C/C++ Source or Header  |  1991-09-09  |  6KB  |  247 lines

  1. /*    expand.c
  2.  *    (c) Copyright 1991 by Ben Eng, All Rights Reserved
  3.  *
  4.  *    macro expansion
  5.  */
  6.  
  7. #include <clib/exec_protos.h>
  8.  
  9. #include <ctype.h>
  10.  
  11. #include "make.h"
  12. #include "depend.h"
  13.  
  14. static int expand_macros2( char *dest, char *src, int maxlen );
  15. static int expand_macros3( char *src, int maxlen );
  16.  
  17. /*    define the criterion for detecting infinitely recursive
  18.  *    macro expansions
  19.  */
  20. static int expand_level = 0;
  21. #define MAX_RECURSION    32
  22. #define MAX_ITERATION    256
  23.  
  24. static struct macro *
  25. expand_fncall( char *src, int maxlen )
  26. {
  27.     static struct macro *fnmac = NULL;
  28.     struct fncall *fc;
  29.     char fn[ 40 ], *next = src;
  30.     int addlen;
  31.  
  32.     if( fnmac) {
  33.         if( fnmac->expansion ) {
  34.             free( fnmac->expansion );
  35.             fnmac->expansion = NULL;
  36.         }
  37.     }
  38.     else if( fnmac = new_macro( NULL, NULL ))
  39.         fnmac->flags |= MF_SIMPLE;
  40.     else return( NULL );
  41.  
  42.     next = parse_str( fn, next, sizeof(fn));
  43.     if( fc = find_fncall( fn )) {
  44.         if( (*fc->call)( fnmac, next )) {
  45.             logprintf( "function call %s returned ERROR\n", fc->name );
  46.             return( NULL );
  47.         }
  48.         fnmac->flags |= MF_SIMPLE;
  49.         return( fnmac );
  50.     }
  51.     return( NULL );
  52. }
  53.  
  54. /*    expand a macro reference with only a single $(x) instance
  55.  *    handles recursive expansion
  56.  */
  57. static int
  58. expand_macros3( char *src, int maxlen )
  59. {
  60.     char *dest = NULL;
  61.     char *macroname = NULL;
  62.     char *dollar;
  63.  
  64.     dollar = strchr( src, '$' );
  65.     if( dollar ) {
  66.         struct macro *mac = NULL;
  67.         char *out, *next;
  68.          int outlen = 0;
  69.         char delimchar = (char)0;
  70.  
  71.         debugprintf( 6,( "expand_macros3(%s,%d)\n", src, maxlen ));
  72.  
  73.         /* could get away with only allocating maxlen to save memory */
  74.         macroname = (char *)malloc( Param.MaxLine );
  75.         dest = (char *)calloc( Param.MaxLine, 1 );
  76.         if( !macroname || !dest )
  77.             goto death;
  78.  
  79.         out = dest;
  80.  
  81.         memset( macroname, 0, Param.MaxLine);
  82.         for( next = src; next < dollar && outlen < maxlen; outlen++ )
  83.             *out++ = *next++;
  84.  
  85.         next = dollar + 1;
  86.         if( outlen >= maxlen )
  87.             goto death;
  88.  
  89.         if( *next == '(' )
  90.             delimchar = ')';
  91.         else if( *next == '{' )
  92.             delimchar = '}';
  93.  
  94.         if( delimchar ) { /* multi letter variable name */
  95.             char *n;
  96.             int i = 0;
  97.  
  98.             for( n = ++next; *n && i < Param.MaxLine-1; n++ ) {
  99.                 if( *n == delimchar ) break;
  100.                 macroname[ i++ ] = *n;
  101.             }
  102.             if( *n != delimchar ) {
  103.                 logprintf( "macro name is too long [%s]\n", macroname );
  104.                 logprintf( "macro names are limited to %d\n",
  105.                     Param.MaxLine );
  106.                 goto death;
  107.             }
  108.             next = n + 1;
  109.         }
  110.         else { /* single letter variable name */
  111.             macroname[ 0 ] = *next++; /* advance past the macroname */
  112.         }
  113.  
  114.         if( mac = expand_fncall( macroname, maxlen - outlen )) {
  115.             debugprintf( 4,( "fncall macro [%s] = %s\n", macroname,
  116.                 mac->expansion ));
  117.         }
  118.         else if( !(mac = find_macro( macroname )) && getenv( macroname )) {
  119.             /* use getenv() to assign a simple macro */
  120.             debugprintf( 4,( "getenv macro [%s]\n", macroname ));
  121.             if( mac = set_macro( macroname, getenv( macroname ))) {
  122.                 mac->flags |= MF_SIMPLE;
  123.             }
  124.         }
  125.         if( mac ) {
  126.             int cdrlen = maxlen - outlen;
  127.             if( mac->flags & MF_EXPANDED ) {
  128.                 logprintf( "infinitely recursive macro expansion: %s\n",
  129.                     macroname );
  130.                 goto death;
  131.             }
  132.             memset( out, 0, cdrlen );
  133.             if( mac->expansion)
  134.                 strncpy( out, mac->expansion, cdrlen );
  135.             cdrlen -= strlen( out );
  136.             if( cdrlen < 0 ) {
  137.                 logprintf( "expand_macros3 ERROR: cdrlen is %d\n",
  138.                     cdrlen );
  139.                 goto death;
  140.             }
  141.             strncpy( out + strlen(out), next, cdrlen );
  142.             if( !(mac->flags & MF_SIMPLE )) {
  143.                 /* recursively expand nested macro expansion */
  144.                 mac->flags |= MF_EXPANDED;
  145.                 if( expand_macros2( out, out, cdrlen )) goto death;
  146.                 mac->flags &= ~MF_EXPANDED;
  147.             }
  148.         }
  149.         else {
  150.             logprintf( "WARNING:  unknown macro [%s]\n", macroname );
  151.             strncpy( out + strlen(out), next, maxlen - outlen );
  152.         }
  153.         /* for next macro occurrence on the line */
  154.         outlen = min( strlen( dest ), maxlen );
  155.  
  156.         debugprintf( 6,( "expand_macros3 returns [%s] %d\n", dest, outlen ));
  157.  
  158.         strncpy( src, dest, outlen ); /* copy the expansion back */
  159.         src[ outlen  ] = (char)0;
  160.         free( macroname ); macroname = NULL;
  161.         free( dest ); dest = NULL;
  162.     } /* dollar */
  163.  
  164.     return( 0 );
  165. death:
  166.     if( macroname )
  167.         free( macroname );
  168.     if( dest )
  169.         free( dest );
  170.     return( 1 );
  171. }
  172.  
  173. /*    find the rightmost occurrence of the character tok
  174.  *    starting at prev in the string
  175.  */
  176. static char *
  177. strrlchr( char *string, char tok, char *prev )
  178. {
  179.     while( prev >= string ) {
  180.         if( *prev == tok ) return( prev );
  181.         prev--;
  182.     }
  183.     return( NULL );
  184. }
  185.  
  186. /*    expand a line with multiple $(x) instances
  187.  *    expand right to left to avoid recursion
  188.  */
  189. static int
  190. expand_macros2( char *dest, char *src, int maxlen )
  191. {
  192.     char *dollar, *prev;
  193.     int iteration = 0;
  194.  
  195.     /* increment the recursion level counter */
  196.     if( ++expand_level > MAX_RECURSION ){
  197.         logprintf( "Infinite Macro expansion aborted at %d recursions\n",
  198.             expand_level );
  199.         return( 1 );
  200.     }
  201.     debugprintf( 6,( "expand_macros2(%s,%d)\n", src, maxlen ));
  202.     if( src != dest ) strncpy( dest, src, maxlen );
  203.     prev = dest + strlen(dest);
  204.     while( dollar = strrlchr( dest, '$', prev )) {
  205.         if( ++iteration > MAX_ITERATION ) {
  206.             logprintf( "Infinite Macro expansion aborted at %d iterations\n",
  207.                 iteration );
  208.             return( 1 );
  209.         }
  210.         if( dollar[-1] == '$' || dollar[-1] == '\\' ) {
  211.             shift_string_left( dollar - 1, 1 );
  212.             --dollar;
  213.         }
  214.         else if( expand_macros3( dollar, maxlen - (int)(dollar - dest) ))
  215.             return( 1 );
  216.         prev = dollar - 1;
  217.     }
  218.     debugprintf( 6,( "expand_macros2 returns [%s]\n", dest ));
  219.     return( 0 );
  220. }
  221.  
  222. /*    to reset each variable's flags before expansion begins */
  223. static long
  224. reset_macroflag( struct macro *mac )
  225. {
  226.     mac->flags &= ~MF_EXPANDED;
  227.     return( 0 );
  228. }
  229.  
  230. /*    top level macro expansion call
  231.  *    this is the entry point called from the outside
  232.  */
  233. int
  234. expand_macros( char *dest, char *src, int maxlen )
  235. {
  236.     expand_level = 0;    /* reset the recursion level counter */
  237.     memset( dest, 0, maxlen );
  238.     for_list( &Global.macrolist, reset_macroflag );
  239.     if( expand_macros2( dest, src, maxlen - 1 )) {
  240.         logprintf( "Error expanding $(%s)\n", src );
  241.         return( 1 );
  242.     }
  243.  
  244.     debugprintf( 3,( "expand_macros [%s] to [%s]\n", src, dest ));
  245.     return( 0 );
  246. }
  247.